package com.foo.web.controller.pay;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foo.common.core.domain.AjaxResult;
import com.foo.common.utils.StringUtils;
import com.foo.common.utils.http.HttpUtils;
import com.foo.web.controller.pay.wxpay.AbstractWxPayApiController;
import com.foo.wechat.domain.WxOrder;
import com.foo.wechat.domain.WxOrderChild;
import com.foo.wechat.service.IWxConfigService;
import com.foo.wechat.service.IWxOrderChildService;
import com.foo.wechat.service.IWxOrderService;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.IpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.model.RefundModel;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>微信支付 Demo</p>
 *
 * @author Javen
 */
@Controller
@RequestMapping("/wechat/api/wxPay")
public class WxPayController extends AbstractWxPayApiController {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    //定义传参
    private static Map<String, Object> mapMSG = new HashMap<>();//向回调发送数据

    @Autowired
    private IWxConfigService configService;
    @Autowired
    private IWxOrderService wxOrderService;
    @Autowired
    private IWxOrderChildService wxOrderChildService;

    @Override
    public WxPayApiConfig getApiConfig() {
        WxPayApiConfig apiConfig;
        apiConfig = WxPayApiConfig.builder()
                .appId(configService.selectConfigByKey("wx_app_id"))
                .mchId(configService.selectConfigByKey("wx_app_mchid"))
                .certPath(configService.selectConfigByKey("cret_file_url"))
                .partnerKey(configService.selectConfigByKey("wx_app_apikey"))
                .domain(configService.selectConfigByKey("domain_url"))
                .apiKey(configService.selectConfigByKey("wx_app_apikey"))
                .build();
        return apiConfig;
    }
    /*---------------------------------------------------------------------------------*/
    /************************************统一下单模块***********************************/
    /*---------------------------------------------------------------------------------*/

    public static Integer DateToTimestamp(Date time) {
        Timestamp ts = new Timestamp(time.getTime());
        return (int) ((ts.getTime()) / 1000);
    }

    /**
     * 订单支付
     */
    @RequestMapping(value = "/pay", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public AjaxResult OrderAppPay(HttpServletRequest request, WxOrder wxOrder, String openId, String totalFee, Integer type) {
        String out_trade_no = WxPayKit.generateStr();
        WxPayApiConfig wxPayApiConfig = getApiConfig();
        mapMSG.put(out_trade_no, wxOrder);
        String notify_url = wxPayApiConfig.getDomain() + "/wechat/api/wxPay/PayNotify";
        return new AjaxResult().success(getConfigMap(out_trade_no, type, openId, "领养定金支付", totalFee, wxPayApiConfig, request, notify_url));
    }

    /**
     * 订单支付
     */
    @RequestMapping(value = "/payChild", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public AjaxResult OrderChildAppPay(HttpServletRequest request, WxOrderChild wxOrderChild, String openId, String totalFee, Integer type) {
        String out_trade_no = WxPayKit.generateStr();
        WxPayApiConfig wxPayApiConfig = getApiConfig();
        mapMSG.put(out_trade_no, wxOrderChild);
        String notify_url = wxPayApiConfig.getDomain() + "/wechat/api/wxPay/PayChildNotify";
        return new AjaxResult().success(getConfigMap(out_trade_no, type, openId, "其他费用支付", totalFee, wxPayApiConfig, request, notify_url));
    }


    /*---------------------------------------------------------------------------------*/
    /************************************回调模块***********************************/

    @RequestMapping(value = "/PayNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String PayNotify(HttpServletRequest request) throws Exception {
        String xmlMsg = HttpKit.readData(request);
        log.info("支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
        if (getNotifyConfig(params)) {
            // 更新订单信息
            String out_trade_no = (String) params.get("out_trade_no");
            try {
                WxOrder wxOrder = (WxOrder) mapMSG.get(out_trade_no);
                wxOrder.setOrderNo(out_trade_no);
                wxOrder.setOrderState(0L);
                wxOrderService.insertWxOrder(wxOrder);
            }catch (Exception e){
                return WxPayKit.toXml(SuccessXml(out_trade_no, "0", "0", 0));
            }finally {
                return WxPayKit.toXml(SuccessXml(out_trade_no, "0", "0", 0));
            }
        }
        return null;
    }


    @RequestMapping(value = "/PayChildNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String PayChildNotify(HttpServletRequest request) throws Exception {
        String xmlMsg = HttpKit.readData(request);
        log.info("支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
        if (getNotifyConfig(params)) {
            // 更新订单信息
            String out_trade_no = (String) params.get("out_trade_no");
            try {
                WxOrderChild wxOrderChild = (WxOrderChild) mapMSG.get(out_trade_no);
                wxOrderChild.setOrderChildNo(out_trade_no);
                wxOrderChildService.insertWxOrderChild(wxOrderChild);

                WxOrder wxOrder  = wxOrderService.selectWxOrderById(wxOrderChild.getOrderChildOid());
                if(wxOrderChild.getOrderChildType()==0){
                    wxOrder.setOrderIsdayfee(wxOrder.getOrderIsdayfee().add(wxOrderChild.getOrderChildFee()));
                    wxOrder.setOrderNodayfee(wxOrder.getOrderNodayfee().subtract(wxOrderChild.getOrderChildFee()));
                    wxOrderService.updateWxOrder(wxOrder);
                }else if(wxOrderChild.getOrderChildType()==1){
                   wxOrder.setOrderState(1L);
                    wxOrderService.updateWxOrder(wxOrder);
                }
            }catch (Exception e){
                return WxPayKit.toXml(SuccessXml(out_trade_no, "0", "0", 0));
            }finally {
                return WxPayKit.toXml(SuccessXml(out_trade_no, "0", "0", 0));
            }
        }
        return null;
    }

    /**
     * 支付配置
     *
     * @param out_trade_no
     * @param type
     * @param openId
     * @param body
     * @param fee
     * @param wxPayApiConfig
     * @param request
     * @param notify_url
     * @return
     */
    public Map<String, ? extends Object> getConfigMap(String out_trade_no, Integer type, String openId, String body, String fee, WxPayApiConfig wxPayApiConfig, HttpServletRequest request, String notify_url) {
        String APPID = configService.selectConfigByKey("wx_app_pay_id");
        String ip = IpKit.getRealIp(request);
        if (StringUtils.isBlank(ip)) {
            ip = "127.0.0.1";
        }
        String appid = "";
        String tradeType = "";
        if (type == 0) {
            appid = wxPayApiConfig.getAppId();
            tradeType = TradeType.JSAPI.getTradeType();
        } else {
            appid = APPID;
            tradeType = TradeType.APP.getTradeType();
        }
        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(appid)
                .mch_id(wxPayApiConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .body(body)
                .out_trade_no(out_trade_no)
                .total_fee(fee)
                .attach("")
                .spbill_create_ip(ip)
                .notify_url(notify_url)
                .trade_type(tradeType)
                .openid(openId)
                .build()
                .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);
        if (type != 0) {
            params.remove("openid");
        }
        String xmlResult = WxPayApi.pushOrder(false, params);
        log.info(xmlResult);
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
        Map<String, Object> mapConfig = new HashMap<>();
        mapConfig.put("params", params);
        mapConfig.put("result", result);
        String returnCode = result.get("return_code");
        String returnMsg = result.get("return_msg");
        if (!WxPayKit.codeIsOk(returnCode)) {
            return new AjaxResult().error(returnMsg);
        }
        String resultCode = result.get("result_code");
        if (!WxPayKit.codeIsOk(resultCode)) {
            return new AjaxResult().error(returnMsg);
        }
        Map<String, String> resultXMl = (Map<String, String>) mapConfig.get("result");
        String prepayId = resultXMl.get("prepay_id");

        Map<String, String> packageParams = null;
        if (type == 0) {
            appid = wxPayApiConfig.getAppId();
            packageParams = WxPayKit.miniAppPrepayIdCreateSign(appid, prepayId,
                    wxPayApiConfig.getPartnerKey(), SignType.MD5);
        } else {
            packageParams = WxPayKit.appPrepayIdCreateSign(APPID, wxPayApiConfig.getMchId(), prepayId,
                    wxPayApiConfig.getPartnerKey(), SignType.MD5);
        }

        return packageParams;
    }


    /**
     * 回调配置
     *
     * @param params
     * @return
     */
    public boolean getNotifyConfig(Map<String, String> params) {
        String returnCode = params.get("return_code");
        if (WxPayKit.verifyNotify(params, getApiConfig().getPartnerKey(), SignType.MD5)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 成功返回
     *
     * @param out_trade_no
     * @param power
     * @param msg
     * @param type
     * @return
     * @throws Exception
     */
    public Map<String, String> SuccessXml(String out_trade_no, String power, String msg, Integer type) throws Exception {
        if (type == 1) {
            com.foo.common.json.JSONObject jsonObject = new com.foo.common.json.JSONObject();
            jsonObject.put("power", power);
            jsonObject.put("msg", msg);
        }
        log.info("支付回调成功");
        mapMSG.remove(out_trade_no);
        Map<String, String> xml = new HashMap<String, String>(2);
        xml.put("return_code", "SUCCESS");
        xml.put("return_msg", "OK");
        return xml;
    }

}
